
#ifndef _Common_h
#define _Common_h

// 系统级
#include "cocos2d.h"
#include "extensions/cocos-ext.h"
#include "cocostudio/CocoStudio.h"
#include "ui/CocosGUI.h"
#include <stdint.h>
#include <iostream>
#include <cstdlib>
#include <string>
#include <sstream>
#include <iomanip>

using namespace cocos2d;
using namespace cocos2d::extension;
using namespace cocos2d::ui;
using namespace cocostudio;
using namespace cocostudio::timeline;

#if USE_AUDIO_ENGINE && USE_SIMPLE_AUDIO_ENGINE
    #error "Don't use AudioEngine and SimpleAudioEngine at the same time. Please just select one in your game!"
#endif

#if USE_AUDIO_ENGINE
    #include "audio/include/AudioEngine.h"
    using namespace cocos2d::experimental;
#elif USE_SIMPLE_AUDIO_ENGINE
    #include "audio/include/SimpleAudioEngine.h"
    using namespace CocosDenshion;
#endif

// 识别是不是64位编译
#if defined(__x86_64__) || defined(__LP64__) || defined(__amd64)
    #define IS_BUILD_FOR_64_BIT     1
#endif

#if defined(ANDROID) || defined(__ANDROID__)
    #include <android/log.h>
    #define  DebugLogWrite(...)  __android_log_print(ANDROID_LOG_ERROR, "debug", __VA_ARGS__)
#else
    inline void DebugLogWrite(const char* format, ...) {
        va_list theArgs;
        va_start(theArgs, format);
        int len = 4 + ((vsnprintf(nullptr, 0, format, theArgs) + 3) & ~3);
        va_end(theArgs);
        va_start(theArgs, format);
        char* buffer = (char*)malloc(len);
        if (buffer) {
            len = vsnprintf(buffer, len, format, theArgs);
            if (len > 0) {
#if defined(WIN32) || defined(WIN64)
                buffer[len] = 0;
                ::OutputDebugStringA(buffer);
#else
                printf("%s", buffer);
#endif
            }
            free(buffer);
        }
        va_end(theArgs);
    }
#endif

#ifndef DEFINE_PROPERTY
    #define DEFINE_PROPERTY(_type, _var, _fun)\
        protected: _type _var; public: virtual _type get##_fun(void) const { return _var; } virtual void set##_fun(_type var){ _var = var; }
#endif

#ifndef DEFINE_PROPERTY_PASS_BY_REF
    #define DEFINE_PROPERTY_PASS_BY_REF(_type, _var, _fun)\
        protected: _type _var; public: virtual const _type& get##_fun(void) const { return _var; } virtual void set##_fun(const _type& var){ _var = var; }
#endif

namespace utility {
    template <typename T>
    inline std::string toString(const T arg)
    {
        std::ostringstream stream;
        if (std::is_integral<T>::value) {
            stream << std::setiosflags(std::ios::fixed) << std::setprecision(0) << arg; // 整数直接转
        } else if(std::is_floating_point<T>::value){
            stream << std::setiosflags(std::ios::fixed) << std::setprecision(3) << arg; // 浮点保留三位小数
        } else {
            stream << arg; // 其他的也直接转
        }
        return stream.str();
    }
    template<>
    inline std::string toString<bool>(const bool arg) {
        return arg ? "true" : "false";
    }
    template <typename T, typename... Types>
    inline std::string toString(const T firstArg, const Types... args) {
        std::ostringstream stream;
        stream << toString(firstArg) << toString(args...);
        return stream.str();
    }
    inline void setSpriteFrame(Sprite* sp, const std::string& name) {
        SpriteFrame* sf = SpriteFrameCache::getInstance()->getSpriteFrameByName(name);
        if (sf && sp) {
            sp->setSpriteFrame(sf);
        }
    }
    inline void ThreadSleep(uint32_t ms) {
        std::this_thread::sleep_for(std::chrono::milliseconds(ms));
    }
}

// 牌型
enum  CARD_TYPE {
    ERROR_CARD = 0               // 错误的牌型
    // 单牌
    , ONLY_CARD                  // 绝对的单牌（可以提供给飞机当作翅膀带出去的牌）
    , SINGLE_CARD                // 单牌，大小顺序从3(最小)到大怪(最大) [单牌数量>=5称作顺子(顺子至少5张连续大小，2和怪不能用)]
    // 对子
    , DOUBLE_CARD                // 对子，两张大小相同的牌 [对子数量>=3称作连对(连对至少3对连续大小，2和怪不能用)]
    // 三张
    , THREE_CARD                 // 3不带，三张大小相同的牌 [三张数量>=2称作飞机]
    , THREE_ONE_CARD             // 3带1，三张并带上任意一张牌
    , THREE_TWO_CARD             // 3带2，三张并带上一对
    // 四张
    , BOMB_CARD                  // 炸弹，四张大小相同的牌，炸弹能盖过除火箭外的其他牌型
    , BOMB_ONE_CARD              // 四张带上一个单张 [四张数量>=2称作大飞机]
    , BOMB_TWO_CARD              // 四张带上两个单张
    , BOMB_TWOO_CARD             // 四张带上1对
    , BOMB_TWOOO_CARD            // 四张带上2对
    // 火箭
    , MISSILE_CARD               // 火箭，也叫作王炸 (一张大王加一张小王构成，大过任何一种牌型)
};

// 每种牌的信息
typedef struct {
    CARD_TYPE             _type;
    std::vector<int32_t>  _cards;
    void toString() {
        // 牌面：3, 4, 5, 6, 7, 8, 9, 10, J, Q,  K,  A,  2, XW, DW
        // 索引：0, 1, 2, 3, 4, 5, 6, 7,  8, 9, 10, 11, 12, 13, 14
        const char* tmp[] = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2", "XW", "DW"};
        switch(_type) {
            case CARD_TYPE::ONLY_CARD : DebugLogWrite("绝对的单牌: "); break;
            case CARD_TYPE::SINGLE_CARD :
                DebugLogWrite((_cards.size() >= 5 ? "顺子: %s" : "单牌: %s"), (_cards.size() >= 5 ? " " : tmp[ _cards[0] ])); break;
            case CARD_TYPE::DOUBLE_CARD : DebugLogWrite(_cards.size() >= 6 ? "连对: " : "对子: "); break;
            case CARD_TYPE::THREE_CARD : DebugLogWrite(_cards.size() >= 6 ? "飞机: " : "三张: "); break;
            case CARD_TYPE::THREE_ONE_CARD : DebugLogWrite(_cards.size() >= 8 ? "飞机带翅膀: " : "三带一: "); break;
            case CARD_TYPE::THREE_TWO_CARD : DebugLogWrite(_cards.size() >= 10 ? "飞机带翅膀: " : "三带二: "); break;
            case CARD_TYPE::BOMB_ONE_CARD : DebugLogWrite(_cards.size() >= 10 ? "大飞机带翅膀: " : "四带一: "); break;
            case CARD_TYPE::BOMB_TWO_CARD : DebugLogWrite(_cards.size() >= 12 ? "大飞机带翅膀: " : "四带二: "); break;
            case CARD_TYPE::BOMB_TWOO_CARD : DebugLogWrite(_cards.size() >= 12 ? "大飞机带翅膀: " : "四带一对: "); break;
            case CARD_TYPE::BOMB_TWOOO_CARD : DebugLogWrite(_cards.size() >= 16 ? "大飞机带翅膀: " : "四带两对: "); break;
            case CARD_TYPE::BOMB_CARD : DebugLogWrite(_cards.size() >= 8 ? "连炸: " : "炸弹: "); break;
            case CARD_TYPE::MISSILE_CARD : DebugLogWrite("火箭: "); break;
            default: DebugLogWrite("???"); break;
        }
        if(CARD_TYPE::SINGLE_CARD != _type || _cards.size() > 1) {
            for (auto&& i : _cards) std::cout << tmp[i] << ", ";
        }
        std::cout << std::endl;
    }
} CARDS_DATA;

#endif
